﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TTEngine.Graphics;
using TTEngine.TTMath;
using Silk.NET.OpenGLES;
using TTEngine.Resource;
using voidbox;
namespace TTEngine.Graphics
{

    //针对单贴图的Batcher,最简单的Batcher结构，非主力结构
    //保留他可以做最简单的功能
    //如果输入图片是一个RGBA，就直接画
    //如果输入图片是Gray，就当作Alpha
    public class SingleTextureBatcher : IBatcher
    {
        public struct DrawPoint
        {
            public float x;
            public float y;
            public float z;
            public float u;
            public float v;
            public byte r;
            public byte g;
            public byte b;
            public byte a;
        }


        private DrawPoint[] _vbobuf = new DrawPoint[4096];
        private int _vbocount = 0;

        //private ITexture _lastTexture = null;


        Mesh _mesh;
        Material _automaterial;
        Material _automaterialFont;

        Material _lastMaterial;
        CommonResource _resource;
        public SingleTextureBatcher(CommonResource package)
        {

            this._resource = package;



        }

        public bool ZWrite = false;
        public bool ZTest = false;
        ITarget target;
        Camera camera;
        public void BeginDraw()
        {

            this.target = TTEngine.Runtime.activeTarget;
            this.camera = TTEngine.Runtime.activeCamera;
            if (_mesh == null)
            {
                _automaterial = new Material(_resource.Package, ResourceAll.GetNamedResource<ShaderProgram>("simple"));
                _automaterialFont = new Material(_resource.Package, ResourceAll.GetNamedResource<ShaderProgram>("simpleGrayAsAlpha"));
                _mesh = new Mesh(_resource.Package);
                _mesh.UpdateVertexFormat(VertexFormatMgr.GetFormat_Vertex_UV_Color());
            }
        }
        public void ResumeDraw()
        {

        }
        public enum DrawMode
        {
            RGBA,
            GrayAsAlpha,
        }

        public void Draw(SingleTextureSprite sprite, fAABB dest, float targetZ, Color32 color)
        {
            Draw(sprite.Texture, sprite.UV, dest, targetZ, color);
        }
        public void Draw(ITexture texture, fAABB uv, fAABB dest, float targetZ, Color32 color)
        {
            if (texture == null)
                return;
            var mat = texture.format == TextureType.R_U8 ? this._automaterialFont : this._automaterial;
            if (_lastMaterial != mat || mat._uniformTexs["tex"].Value != texture)
            {
                EndDraw();
                mat._uniformTexs["tex"].Value = texture;
            }


            Draw(mat, uv, dest, targetZ, color);

        }
        private PrimitiveType _lastMode;
        public void DrawLine(System.Numerics.Vector2 p0, System.Numerics.Vector2 p1, float z, Color32 color)
        {
            DrawPoint ip0 = new DrawPoint();
            ip0.x = p0.X;
            ip0.y = p0.Y;
            ip0.z = z;
            ip0.u = 0;
            ip0.v = 0;
            ip0.r = color.r;
            ip0.g = color.g;
            ip0.b = color.b;
            ip0.a = color.a;
            DrawPoint ip1 = new DrawPoint();
            ip1.x = p1.X;
            ip1.y = p1.Y;
            ip1.z = z;
            ip1.u = 0;
            ip1.v = 0;
            ip1.r = color.r;
            ip1.g = color.g;
            ip1.b = color.b;
            ip1.a = color.a;
            var mat = _automaterial;
            mat._uniformTexs["tex"].Value =_resource.TexWhite;
            DrawLine(mat, ip0, ip1);
        }

        public void DrawLine(Material mat, DrawPoint p0, DrawPoint p1)
        {
            if (target == null)
                throw new Exception("RenderBatcher Not in Begin-End.");

            if (_lastMode != PrimitiveType.Lines
                || _lastMaterial != mat
                || _vbocount > 4096 - 2)
            {
                EndDraw();
                _lastMaterial = mat;
            }
            _lastMode = PrimitiveType.Lines;

            _vbobuf[_vbocount] = p0; _vbocount++;
            _vbobuf[_vbocount] = p1; _vbocount++;

        }
        //使用自定义材质绘制
        public void Draw(Material material, fAABB uv, fAABB dest, float targetZ, Color32 color)
        {
            if (material == null)
                return;

            if (_lastMaterial != material
                || _vbocount > 4096 - 6
                || _lastMode != PrimitiveType.Triangles
                )
            {
                EndDraw();
            }
            _lastMaterial = material;
            _lastMode = PrimitiveType.Triangles;
            var p0 = new DrawPoint();
            p0.x = dest.x1;
            p0.y = dest.y1;
            p0.z = targetZ;
            p0.u = uv.x1;
            p0.v = uv.y1;
            p0.r = (byte)(color.r);
            p0.g = (byte)(color.g);
            p0.b = (byte)(color.b);
            p0.a = (byte)(color.a);
            var p1 = new DrawPoint();
            p1.x = dest.x2;
            p1.y = dest.y1;
            p1.z = targetZ;
            p1.u = uv.x2;
            p1.v = uv.y1;
            p1.r = (byte)(color.r);
            p1.g = (byte)(color.g);
            p1.b = (byte)(color.b);
            p1.a = (byte)(color.a);
            var p2 = new DrawPoint();
            p2.x = dest.x1;
            p2.y = dest.y2;
            p2.z = targetZ;
            p2.u = uv.x1;
            p2.v = uv.y2;
            p2.r = (byte)(color.r);
            p2.g = (byte)(color.g);
            p2.b = (byte)(color.b);
            p2.a = (byte)(color.a);
            var p3 = new DrawPoint();
            p3.x = dest.x2;
            p3.y = dest.y2;
            p3.z = targetZ;
            p3.u = uv.x2;
            p3.v = uv.y2;
            p3.r = (byte)(color.r);
            p3.g = (byte)(color.g);
            p3.b = (byte)(color.b);
            p3.a = (byte)(color.a);
            _vbobuf[_vbocount] = p0; _vbocount++;
            _vbobuf[_vbocount] = p1; _vbocount++;
            _vbobuf[_vbocount] = p2; _vbocount++;
            _vbobuf[_vbocount] = p2; _vbocount++;
            _vbobuf[_vbocount] = p1; _vbocount++;
            _vbobuf[_vbocount] = p3; _vbocount++;
        }
        public void DrawFont(FontAscII12 font, string text, float x, float y, float z, Color color, float scale = 2, float wordspace = 0)
        {
            if (font == null)
                return;

            foreach (var t in text)
            {
                if (font.TryGetUV(t, out var uv))
                {
                    Draw(font.texFont, uv, new fAABB(x, y, x + 6 * scale, y + 12 * scale), 0, color);
                    x += font.FontSize / 2 * scale + wordspace;
                }
                else if (t == ' ')
                    x += font.FontSize / 2 * scale;
            }
        }

        public void EndDraw()
        {
            //改写为标准的Render写法
            if (_lastMaterial == null || _vbocount == 0)
                return;
            _lastMaterial.ZTest = ZTest;
            _lastMaterial.ZWrite = ZWrite;
            _lastMaterial.UpdateMatProj(target);
            _lastMaterial.UpdateMatView(camera.GetViewMatrix());
            //_lastMaterial.Apply();

            _mesh.Mode = _lastMode;
            _mesh.UploadVertexBuffer(0, _vbobuf, true, 24 * _vbocount);
            _mesh.Draw(_lastMaterial);
            Runtime.activeTarget.RenderInfo.DrawCount++;
            Runtime.activeTarget.RenderInfo.DrawElemCount += (uint)_vbocount / 3;
            _lastMaterial = null;

            _vbocount = 0;
        }
    }
}

